#include "MaterialSetting.h"

MaterialSetting::MaterialSetting(obj* obj, QWidget* parent)
	: QDialog(parent)
{
	object = obj;
	view = QPixmap(128, 128);
	ui.setupUi(this);
	preview.cam = Camera(128, 128);
	preview.objlist.append(new Sphere("Preview Sphere", vec(3, 0, 0), 1));

	updateMatList();

	ui.listWidget->setProperty("contextMenuPolicy", Qt::CustomContextMenu);
	ui.TexListWidget->setProperty("contextMenuPolicy", Qt::CustomContextMenu);

	materialMenu = new QMenu(this);
	addMatMenu = new QMenu(tr("Add Material"), this);
	addDiffuse = new QAction(tr("Add Diffuse"));
	addMirror = new QAction(tr("Add Mirror"));
	addMetal = new QAction(tr("Add Metal"));
	addFlat = new QAction(tr("Add Flat"));
	addEmission = new QAction(tr("Add Emission"));
	deleteMat = new QAction(tr("Delete Material"));
	renameMat = new QAction(tr("Rename Material"));

	addMatMenu->addAction(addDiffuse);
	addMatMenu->addAction(addMirror);
	addMatMenu->addAction(addMetal);
	addMatMenu->addAction(addFlat);
	addMatMenu->addAction(addEmission);
	materialMenu->addMenu(addMatMenu);
	materialMenu->addAction(deleteMat);
	materialMenu->addAction(renameMat);

	texMenu = new QMenu(this);
	addTexMenu = new QMenu(tr("Add Texture"), this);
	addPureColor = new QAction(tr("Add Pure Color"));
	addCheckbox = new QAction(tr("Add Checkbox"));
	deleteTex = new QAction(tr("Delete Texture"));
	renameTex = new QAction(tr("Rename Texture"));

	addTexMenu->addAction(addPureColor);
	addTexMenu->addAction(addCheckbox);
	texMenu->addMenu(addTexMenu);
	texMenu->addAction(deleteTex);
	texMenu->addAction(renameTex);


	connect(ui.listWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onMatListMenuRequested(const QPoint&)));
	connect(addDiffuse, SIGNAL(triggered()), this, SLOT(onCreateDiffuse()));
	connect(addMirror, SIGNAL(triggered()), this, SLOT(onCreateMirror()));
	connect(addMetal, SIGNAL(triggered()), this, SLOT(onCreateMetal()));
	connect(addFlat, SIGNAL(triggered()), this, SLOT(onCreateFlat()));
	connect(addEmission, SIGNAL(triggered()), this, SLOT(onCreateEmission()));
	connect(deleteMat, SIGNAL(triggered()), this, SLOT(onDeleteMat()));
	connect(renameMat, SIGNAL(triggered()), this, SLOT(onRenameMat()));
	connect(ui.listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onSelectMat()));
	connect(ui.roughnessSlider, SIGNAL(valueChanged(int)), this, SLOT(onRoughnessChanging(int)));
	connect(ui.roughnessSlider, SIGNAL(sliderReleased()), this, SLOT(onRoughnessChanged()));

	connect(ui.TexListWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onTexListMenuRequested(const QPoint&)));
	connect(addPureColor, SIGNAL(triggered()), this, SLOT(onCreatePureColor()));
	connect(addCheckbox, SIGNAL(triggered()), this, SLOT(onCreateCheckbox()));
	connect(deleteTex, SIGNAL(triggered()), this, SLOT(onDeleteTex()));
	connect(renameTex, SIGNAL(triggered()), this, SLOT(onRenameTex()));
	connect(ui.TexListWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onSelectTex()));
	connect(ui.TexListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(onEditTex(QListWidgetItem*)));

	connect(this, SIGNAL(accepted()), this, SLOT(onApply()));
}


void MaterialSetting::onMatListMenuRequested(const QPoint& pos)
{
	int count = ui.listWidget->selectedItems().count();
	if (count < 1)
	{
		deleteMat->setEnabled(false);
		renameMat->setEnabled(false);
	}
	else if (count != 1) {
		deleteMat->setEnabled(true);
		renameMat->setEnabled(false);
	}
	else
	{
		deleteMat->setEnabled(true);
		renameMat->setEnabled(true);
	}

	materialMenu->exec(QCursor::pos());
}

void MaterialSetting::onTexListMenuRequested(const QPoint& pos)
{
	int count = ui.TexListWidget->selectedItems().count();
	if (count < 1)
	{
		deleteTex->setEnabled(false);
		renameTex->setEnabled(false);
	}
	else if (count != 1) {
		deleteTex->setEnabled(true);
		renameTex->setEnabled(false);
	}
	else
	{
		deleteTex->setEnabled(true);
		renameTex->setEnabled(true);
	}

	texMenu->exec(QCursor::pos());
}

void MaterialSetting::onCreateDiffuse()
{
	material* newMat = new Diffuse(tr("new Diffuse Material"), defaultTex);
	QListWidgetItem* newItem = new QListWidgetItem(newMat->name);
	matMap.insert(newItem, newMat);
	matList.append(newMat);
	ui.listWidget->addItem(newItem);
}
void MaterialSetting::onCreateMirror()
{
	material* newMat = new Mirror(tr("new Mirror Material"));
	QListWidgetItem* newItem = new QListWidgetItem(newMat->name);
	matMap.insert(newItem, newMat);
	matList.append(newMat);
	ui.listWidget->addItem(newItem);
}
void MaterialSetting::onCreateMetal()
{
	material* newMat = new Metal(tr("new Metal Material"), defaultTex);
	QListWidgetItem* newItem = new QListWidgetItem(newMat->name);
	matMap.insert(newItem, newMat);
	matList.append(newMat);
	ui.listWidget->addItem(newItem);
}
void MaterialSetting::onCreateFlat()
{
	material* newMat = new Flat(tr("new Flat Material"), defaultTex);
	QListWidgetItem* newItem = new QListWidgetItem(newMat->name);
	matMap.insert(newItem, newMat);
	matList.append(newMat);
	ui.listWidget->addItem(newItem);
}
void MaterialSetting::onCreateEmission()
{
	material* newMat = new Emission(tr("new Emission Material"), defaultTex);
	QListWidgetItem* newItem = new QListWidgetItem(newMat->name);
	matMap.insert(newItem, newMat);
	matList.append(newMat);
	ui.listWidget->addItem(newItem);
}

void MaterialSetting::onDeleteMat()
{
	QList<QListWidgetItem*> items = ui.listWidget->selectedItems();
	if (items.count() > 0)
	{
		QApplication::beep();
		if (QMessageBox::Yes == QMessageBox::question(this, QString(tr("Remove Item")),
			QString(tr("Remove %1 item")).arg(QString::number(items.count())), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
		{
			foreach(QListWidgetItem * var, items) {
				ui.listWidget->removeItemWidget(var);
				matList.removeOne(matMap.value(var));
				matMap.remove(var);
				items.removeOne(var);
				delete var;
			}
		}
	}
}

void MaterialSetting::onRenameMat()
{
	if (ui.listWidget->currentItem() != NULL)
	{
		QString dlgTitle = tr("Rename Material");
		QString txtLabel = tr("Please enter the name of the material");
		QString defaultInput = matMap.value(ui.listWidget->currentItem())->name;
		QLineEdit::EchoMode echoMode = QLineEdit::Normal;
		bool ok = false;
		QString text = QInputDialog::getText(this, dlgTitle, txtLabel, echoMode, defaultInput, &ok);
		if (ok && !text.isEmpty())
		{
			matMap.value(ui.listWidget->currentItem())->name = text;
			ui.listWidget->currentItem()->setText(text);
		}

	}
}


void MaterialSetting::onSelectMat()
{
	if (ui.listWidget->currentItem() != NULL)
	{
		selectedMat = matMap[ui.listWidget->currentItem()];
		if (selectedMat->type == materialType::MTL)
		{
			ui.roughnessSlider->setEnabled(true);
			ui.label->setText(tr("Roughness"));
			ui.roughnessSlider->setValue(((Metal*)selectedMat)->roughness * 100);
			ui.TexListWidget->setEnabled(true);
			for (QMap<QListWidgetItem*, texture*>::iterator it = texMap.begin(); it != texMap.end(); it++)
			{
				if (it.value() == selectedMat->color)
				{
					ui.TexListWidget->setCurrentItem(it.key());
				}
			}
		}
		else if (selectedMat->type == materialType::MIR)
		{
			ui.roughnessSlider->setEnabled(false);
			ui.TexListWidget->setEnabled(false);
		}
		else if (selectedMat->type == materialType::EMT)
		{
			ui.roughnessSlider->setEnabled(true);
			ui.roughnessSlider->setValue(((Emission*)selectedMat)->scale);
			ui.label->setText(tr("Scale"));
			ui.TexListWidget->setEnabled(true);
			for (QMap<QListWidgetItem*, texture*>::iterator it = texMap.begin(); it != texMap.end(); it++)
			{
				if (it.value() == selectedMat->color)
				{
					ui.TexListWidget->setCurrentItem(it.key());
				}
			}
		}
		else
		{
			ui.roughnessSlider->setEnabled(false);
			ui.TexListWidget->setEnabled(true);
			for (QMap<QListWidgetItem*, texture*>::iterator it = texMap.begin(); it != texMap.end(); it++)
			{
				if (it.value() == selectedMat->color)
				{
					ui.TexListWidget->setCurrentItem(it.key());
				}
			}
		}
		preview.objlist[0]->mat = selectedMat;
		view = rend(preview, 30, 3);
		ui.view->setPixmap(view);
	}
}

void MaterialSetting::onRoughnessChanging(int value)
{
	if (selectedMat != NULL && selectedMat->type == materialType::MTL)
	{
		((Metal*)selectedMat)->roughness = 1. * value / 100;
		preview.objlist[0]->mat = selectedMat;
	}
	else if (selectedMat != NULL && selectedMat->type == materialType::EMT)
	{
		((Emission*)selectedMat)->scale = value;
		preview.objlist[0]->mat = selectedMat;
	}
}

void MaterialSetting::onRoughnessChanged()
{
	view = rend(preview, 30, 3);
	ui.view->setPixmap(view);
}



void MaterialSetting::onCreatePureColor()
{
	texture* newTex = new pureColor(tr("New Pure Color"), Qt::white);
	QListWidgetItem* newItem = new QListWidgetItem(newTex->name);
	texMap.insert(newItem, newTex);
	texList.append(newTex);
	ui.TexListWidget->addItem(newItem);
}

void MaterialSetting::onCreateCheckbox()
{
	texture* newTex = new checkBox(tr("New Checkbox"), Qt::white, Qt::blue);
	QListWidgetItem* newItem = new QListWidgetItem(newTex->name);
	texMap.insert(newItem, newTex);
	texList.append(newTex);
	ui.TexListWidget->addItem(newItem);
}

void MaterialSetting::onSelectTex()
{
	if (ui.TexListWidget->currentItem() != NULL && selectedMat != NULL)
	{
		selectedTex = texMap[ui.TexListWidget->currentItem()];
		selectedMat->color = selectedTex;
		view = rend(preview, 30, 3);
		ui.view->setPixmap(view);
	}
}

void MaterialSetting::onEditTex(QListWidgetItem* item)
{
	switch (texMap[item]->type)
	{
	case texType::PUR:
	{
		QColorDialog cd;
		bool ok = false;
		QColor color = cd.getColor(Qt::white, this, tr("Texture color"));
		((pureColor*)texMap[item])->color = color2vec(color);
		break;
	}
	case texType::CKB:
	{
		CheckboxSetting* cs = new CheckboxSetting((checkBox*)texMap[item], this);
		cs->exec();
		delete cs;
	}
	}
	view = rend(preview, 30, 3);
	ui.view->setPixmap(view);
}

void MaterialSetting::onDeleteTex()
{
	QList<QListWidgetItem*> items = ui.TexListWidget->selectedItems();
	if (items.count() > 0)
	{
		QApplication::beep();
		if (QMessageBox::Yes == QMessageBox::question(this, QString(tr("Remove Item")),
			QString(tr("Remove %1 item")).arg(QString::number(items.count())), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
		{
			foreach(QListWidgetItem * var, items) {

				foreach(material * mat, matList) {
					if (mat->color == texMap.value(var)) mat->color = defaultTex;
				}
				ui.TexListWidget->removeItemWidget(var);
				texList.removeOne(texMap.value(var));
				texMap.remove(var);
				items.removeOne(var);
				delete var;
			}
		}
	}
}

void MaterialSetting::onRenameTex()
{
	if (ui.TexListWidget->currentItem() != NULL)
	{
		QString dlgTitle = tr("Rename Texture");
		QString txtLabel = tr("Please enter the name of the texture");
		QString defaultInput = texMap.value(ui.TexListWidget->currentItem())->name;
		QLineEdit::EchoMode echoMode = QLineEdit::Normal;
		bool ok = false;
		QString text = QInputDialog::getText(this, dlgTitle, txtLabel, echoMode, defaultInput, &ok);
		if (ok && !text.isEmpty())
		{
			texMap.value(ui.TexListWidget->currentItem())->name = text;
			ui.TexListWidget->currentItem()->setText(text);
		}
	}
}

void MaterialSetting::onApply()
{
	if (selectedMat == NULL)
	{
		object->mat = defaultMat;
	}
	else
	{
		object->mat = selectedMat;
	}
}

void MaterialSetting::updateMatList()
{
	ui.listWidget->clear();
	matMap.clear();
	for each (material * var in matList)
	{
		QListWidgetItem* newItem = new QListWidgetItem(var->name);
		matMap.insert(newItem, var);
		ui.listWidget->addItem(newItem);
		if (object->mat == var)
		{
			ui.listWidget->setCurrentItem(newItem);
			onSelectMat();
		}
	}
	updateTexList();
}

void MaterialSetting::updateTexList()
{
	ui.TexListWidget->clear();
	texMap.clear();

	for each (texture * var in texList)
	{
		QListWidgetItem* newItem = new QListWidgetItem(var->name);
		texMap.insert(newItem, var);
		ui.TexListWidget->addItem(newItem);
		if (selectedMat != NULL && selectedMat->color == var)
		{
			ui.TexListWidget->setCurrentItem(newItem);
		}
	}
}
